import pygame
import sys

from pygame.sprite import DirtySprite, LayeredDirty

from state_manager import *
from settings_manager import *
from button import *
from events import *

from animation import Animation
from obstacle import Obstacle
from level_resources import LevelResources

from player import Player
from submit_score import SubmitScore

from collections import deque

import copy

path = "data/textures/"

tiles = 15
INF = (1 << 30)

class GameScene:
	refresh = False

	def __init__(self, screen):
		self.screen = screen

		self.p0 = {"up":False, "down":False, "left":False, "right":False}
		self.p1 = copy.copy(self.p0)

		#Submision
		self.submitScore = SubmitScore(self.screen)

	def create(self):
		self.group = LayeredDirty()

		self.currentTime = pygame.time.get_ticks()
		self.firstTIme = True

		self.currentLevel = 1
		self.map = []
		self.obstacles = dict()
		self.width, self.height = SettingsManager.settings.resolution[0] / tiles, SettingsManager.settings.resolution[0] / tiles

		#BF map
		self.dp = []
		self.father = []
		for i in xrange(15):
			self.dp.append([INF] * tiles)
			self.father.append([(0, 0)] * tiles)

		#Level Loading
		self.loadLevel()


	def loadLevel(self):
		LevelResources.init()
		LevelResources.loadLevelResources(self.currentLevel)

		with open("data/maps/" + "level" + str(self.currentLevel), "r") as f:
			for line in f:
				aux = line.split()
				if len(aux) == 0:
					break

				self.map.append(map(int,aux))

		tileSize = SettingsManager.settings.resolution[0] / tiles
		y = 0
		for i in xrange(tiles):
			x = 0
			aux = []
			for j in xrange(tiles):
				if self.map[i][j]:
					self.obstacles[(j, i)] = Obstacle(self.screen, LevelResources.obImages[self.map[i][j] - 1], x, y, self.map[i][j])	#image, x, y, map[i][j]
				x += tileSize
			y += tileSize

		self.group.add([self.obstacles[x] for x in self.obstacles.keys()])
		#for k in GameScene.obstacles.keys():
		#	GameScene.obstacles[k].hit()

		#Create and position the 2 players 
		self.players = []
		self.players.append(Player(self.screen, 0, 0, 0, self.group, 0))
		self.players.append(Player(self.screen, 1, (tiles - 1) * self.width, (tiles - 1) * self.height, self.group, 1))
		self.players[0].setEnemies([self.players[1]])
		self.players[1].setEnemies([self.players[0]])

		for player in self.players:
			player.setObPl(self.obstacles, self.players)

	def update(self):
		self.submitScore.update()

		if StateManager.state.window != StateConst.Game:
			return None #Escape settings updating

		if GameScene.refresh:
			GameScene.refresh = False
			self.create()

		self.manageEvents()

		self.drawGame()

		self.gameLogic()


	def prepareExit(self):
		StateManager.changeWindow(StateConst.MainMenu)
		StateManager.changeSound(StateConst.SettingsSound)

	def manageEvents(self):
		for event in Events.events:
			if event.type == pygame.KEYUP:
				if event.key == pygame.K_ESCAPE:
					self.prepareExit()

	def gameLogic(self):
		for event in Events.events:
			if event.type == pygame.KEYDOWN:
				if event.key == pygame.K_UP:
					self.p0["up"] = True and not (self.p0["left"] or self.p0["right"])
				elif event.key == pygame.K_DOWN:
					self.p0["down"] = True and not (self.p0["left"] or self.p0["right"])
				elif event.key == pygame.K_LEFT:
					self.p0["left"] = True and not (self.p0["up"] or self.p0["down"])
				elif event.key == pygame.K_RIGHT:
					self.p0["right"] = True	and not (self.p0["up"] or self.p0["down"])

				if not SettingsManager.settings.multiplayer:
					continue

				if event.key == pygame.K_w:
					self.p1["up"] = True and not (self.p1["left"] or self.p1["right"])
				elif event.key == pygame.K_s:
					self.p1["down"] = True and not (self.p1["left"] or self.p1["right"])
				elif event.key == pygame.K_a:
					self.p1["left"] = True and not (self.p1["up"] or self.p1["down"])
				elif event.key == pygame.K_d:
					self.p1["right"] = True and not (self.p1["up"] or self.p1["down"])
			
			if event.type == pygame.KEYUP:
				if event.key == pygame.K_UP:
					self.p0["up"] = False
				elif event.key == pygame.K_DOWN:
					self.p0["down"] = False
				elif event.key == pygame.K_LEFT:
					self.p0["left"] = False
				elif event.key == pygame.K_RIGHT:
					self.p0["right"] = False

				#Plant the bomb
				if event.key == pygame.K_SPACE:
					self.players[0].plantBomb()

				if not SettingsManager.settings.multiplayer:
					continue

				if event.key == pygame.K_w:
					self.p1["up"] = False
				elif event.key == pygame.K_s:
					self.p1["down"] = False
				elif event.key == pygame.K_a:
					self.p1["left"] = False
				elif event.key == pygame.K_d:
					self.p1["right"] = False

				#Plant the bomb
				if event.key == pygame.K_g:
					self.players[1].plantBomb()

		for k in self.p0.keys():
			if self.p0[k] and self.players[0].alive:
				self.players[0].move(k)

		if SettingsManager.settings.multiplayer:
			for k in self.p1.keys():
				if self.p1[k] and self.players[1].alive:
					self.players[1].move(k)
		else:
				#AIIIIII dummy
				if self.firstTIme:
					self.firstTIme = False
					self.bf(self.players[0].getPosCentered())
				elif pygame.time.get_ticks() - self.currentTime > 1000:
					self.currentTime = pygame.time.get_ticks()
					self.bf(self.players[0].getPosCentered())

				if self.players[1].getPosCentered() != self.players[0].getPosCentered():
					if not self.players[1].auto:
						self.players[1].auto = True
						aux = self.players[1].fromCell = self.players[1].getPosCentered()
						self.players[1].toCell = self.father[aux[0]][aux[1]]
						
				else:
					self.players[1].plantBomb()


				self.players[1].moveFromCellToCell()


		for player in self.players:
			player.update()
			if not player.alive:	#Submit score
				StateManager.changeWindow(StateConst.SubmitScore)
				SubmitScore.refresh = True
				SubmitScore.pWin = (player.pNr ^ 1) + 1
				SubmitScore.points = self.players[player.pNr ^ 1].points


	def getPosCentered(self, pos):
		return int((pos[0] + self.width / 2) / self.width), int((pos[1] + self.height / 2) / self.height)
		
	def bf(self, pos):
		Q = deque()

		Q.append(pos)

		_X = [0, 0, 1, -1]
		_Y = [1, -1, 0, 0]

		for i in xrange(15):
			for j in xrange(15):
				self.dp[i][j] = INF

		self.dp[pos[0]][pos[1]] = 0

		while len(Q):
			current = Q.popleft()

			for i in xrange(4):
				x = current[0] + _X[i]
				y = current[1] + _Y[i]

				if self.check((x, y)) and self.dp[x][y] > self.dp[current[0]][current[1]] + 1:
					self.dp[x][y] = self.dp[current[0]][current[1]] + 1
					self.father[x][y] = current
					Q.append((x, y))

	def check(self, position):
		if 0 <= position[0] and position[0] < tiles and 0 <= position[1] and position[1] < tiles and ((not (position in self.obstacles)) or ((position in self.obstacles) and self.obstacles[position].destroyed)):
			return True
		return False

	def drawGame(self):
		self.group.clear(self.screen, LevelResources.background)
		update_area = self.group.draw(self.screen)
		pygame.display.update(update_area)
		self.group.update()
